package com.itheima.appserver.service;
import com.itheima.commons.pojo.domain.Question;
import com.itheima.commons.pojo.domain.UserInfo;
import com.itheima.commons.pojo.mongo.NearUserVo;
import com.itheima.commons.pojo.mongo.RecommendUser;
import com.itheima.commons.pojo.mongo.UserLike;
import com.itheima.commons.pojo.mongo.Visitors;
import com.itheima.dubbo.interfaces.*;
import org.bson.types.ObjectId;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.appserver.config.HuanxinConfig;
import com.itheima.appserver.excepiton.BusinessException;
import com.itheima.appserver.excepiton.ErrorResult;
import com.itheima.appserver.interceptor.UserThreadLocal;
import com.itheima.commons.constants.Constants;
import com.itheima.commons.vo.reception.PageResult;
import com.itheima.commons.vo.reception.TodayBest;
import com.itheima.commons.vo.reception.UserLocationVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author yaohu
 * @date 2021/12/6
 * @Version 1.0
 * @describe
 */
@Service
public class TanhuaService {

    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private RecommendUserApi recommendUserApi;

    @Reference
    private QuestionApi questionApi;

    @Reference
    private UserLocationApi userLocationApi;

    @Reference
    private UserLikeApi userLikeApi;

    @Reference
    private VisitorsApi visitorsApi;

    @Autowired
    private RequestService requestService;

    @Autowired
    private HuanxinConfig huanxinConfig;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * @return 今日佳人
     */
    public TodayBest todayBest() {

        // 1.根据id查询最高缘分值
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(UserThreadLocal.getUserId());

        // 数据库固定间隔计算一次recommend_user表
        // 两次计算间隔注册的人没有推荐人 查询结果为空
        if (ObjectUtil.isNull(recommendUser)) {
            throw new BusinessException(ErrorResult.recommendUserIsEmpty());
        }

        // 2.根据最高缘分值对应的userId查询出详细信息
        UserInfo userInfo = userInfoApi.findUserInfoByUserId(recommendUser.getUserId());

        // 3.把第1步与第2步查询的结果集 合并成一个vo
        return TodayBest.init(userInfo, recommendUser);
    }

    public PageResult recommendationList(Map<String, Object> params) {

        // 1.根据id分页查询推荐用户
        PageResult pageResult = recommendUserApi.queryRecommendUserList(
                MapUtil.getInt(params, "page", 1),
                MapUtil.getInt(params, "pagesize", 10),
                UserThreadLocal.getUserId());

        // 获取数据集合
        List<RecommendUser> items = (List<RecommendUser>) pageResult.getItems();

        // 两次计算间隔注册的人没有推荐人 查询结果为空
        if (CollUtil.isEmpty(items)) {
            throw new BusinessException(ErrorResult.recommendUserIsEmpty());
        }

        // 2.获取推荐人集合的userIds，查询userInfo
        List<Long> userIds = CollUtil.getFieldValues(items, "userId", Long.class);

        UserInfo userInfo = new UserInfo();
        userInfo.setSex(MapUtil.getStr(params, "gender"));
        userInfo.setAge(MapUtil.getInt(params, "age"));
        userInfo.setCity(MapUtil.getStr(params, "city"));
        userInfo.setEdu(MapUtil.getStr(params, "education"));

        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(userInfo, userIds);

        // 有可能查不到符合的信息 为空 返回空集合对象
        if (MapUtil.isEmpty(userInfoMap)) {
            pageResult.setItems(Collections.emptyList());
            return pageResult;
        }

        // 把第1步和第2步的结果集 结合到一个vo中
        ArrayList<TodayBest> todayBests = new ArrayList<>();

        for (RecommendUser recommendUser : items) {
            // 分页查询要求10条 只有3条符合
            TodayBest best = TodayBest.init(userInfoMap.get(recommendUser.getUserId()), recommendUser);
            if (ObjectUtil.isNotNull(best)) {
                todayBests.add(best);
            }
        }
        pageResult.setItems(todayBests);
        return pageResult;
    }

    /**
     * 查询个人主页的个人信息
     *
     * @param userId
     * @return
     */
    public TodayBest queryUserInfo(Long userId) {
        // 保存来访者信息
        Visitors visitors = new Visitors();
        visitors.setId(new ObjectId());
        visitors.setUserId(userId);
        visitors.setVisitorUserId(UserThreadLocal.getUserId());
        visitors.setFrom("个人主页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setScore(0.0D);
        visitorsApi.saveVisitor(visitors);

        // 根据用户id查询用户详细信息
        UserInfo userInfo = userInfoApi.findUserInfoByUserId(userId);
        // 查两个用户的缘分值
        Long fateValue = recommendUserApi.queryScoreByUserId(UserThreadLocal.getUserId(), userId);

        TodayBest todayBest = new TodayBest();
        todayBest.setId(userInfo.getUserId());
        todayBest.setAvatar(userInfo.getLogo());
        todayBest.setNickname(userInfo.getNickName());
        todayBest.setGender(userInfo.getSex() == 1 ? "man" : "woman");
        todayBest.setAge(userInfo.getAge());
        todayBest.setTags(StrUtil.splitToArray(userInfo.getTags(), ","));
        todayBest.setFateValue(fateValue);

        return todayBest;
    }

    /**
     * 根据一个人的id查询他设置的问题
     *
     * @param userId
     * @return
     */
    public String queryQuestion(Long userId) {
        Question question = questionApi.findQuestionByUserId(userId);
        if (ObjectUtil.isNull(question)) {
            question.setTxt("你的爱好是什么？");
            questionApi.saveQuestion(question);
        }
        return question.getTxt();
    }

    /**
     * 回答陌生人问题
     *
     * @param userId 陌生人id
     * @param reply  回答
     */
    public void replyQuestion(Long userId, String reply) {
        /*
            {
                "userId":1, 申请人id
                "huanXinId":"HX_1", 申请人环信id
                "nickname":"黑马小妹", 申请人昵称
                "strangerQuestion":"你喜欢去看蔚蓝的大海还是去爬巍峨的高山？", 被申请人问题
                "reply":"我喜欢秋天的落叶，夏天的泉水，冬天的雪地，只要有你一切皆可~" 申请人回答
            }
         */
        // 查询申请人的信息
        UserInfo userInfo = userInfoApi.findUserInfoByUserId(UserThreadLocal.getUserId());
        // 查询被申请人的问题
        Question question = questionApi.findQuestionByUserId(userId);
        // 组合数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId", userInfo.getUserId());
        map.put("huanXinId", "HX_" + userInfo.getUserId());
        map.put("nickname", userInfo.getNickName());
        map.put("strangerQuestion", question.getTxt());
        map.put("reply", reply);

        // 给环信发送请求 让环信实现通信
        // /{org_name}/{app_name}/messages
        // {"target_type": "users","target": ["user2","user3"],"msg": {"type": "txt","msg": "testmessage"},"from": "user1"}
        HttpResponse response = requestService.execute(huanxinConfig.getUrl() + huanxinConfig.getOrgName() + "/" + huanxinConfig.getAppName() + "/messages",
                JSONUtil.createObj().set("target_type", "users")
                        .set("target", JSONUtil.createArray().put("HX_" + userId))
                        .set("msg", JSONUtil.createObj().set("type", "txt").set("msg", JSONUtil.toJsonStr(map))).toString(),
                Method.POST);
        if (!response.isOk()) {
            throw new BusinessException(ErrorResult.sendHXMsgError());
        }
    }

    /**
     * 上传/更新用户位置信息
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param address   位置信息
     */
    public void updateLocation(Double longitude, Double latitude, String address) {
        userLocationApi.updateUserLocation(UserThreadLocal.getUserId(), longitude, latitude, address);
    }

    /**
     * 搜附近的人
     *
     * @param gender   筛选性别
     * @param distance 筛选距离
     * @return
     */
    public List<NearUserVo> queryNearUser(String gender, Double distance) {
        // 1.查询自己的位置信息
        UserLocationVo userLocationVo = userLocationApi.queryByUserId(UserThreadLocal.getUserId());
        // 2.搜索附近的人
        List<UserLocationVo> userLocationVos = userLocationApi.queryUserFromLocation(
                userLocationVo.getLongitude(), userLocationVo.getLatitude(), distance, 50);
        // 3.提取附近的人的ID
        List<Long> userIds = CollUtil.getFieldValues(userLocationVos, "userId", Long.class);
        // 4.查询tb_user_info
        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(
                UserInfo.builder().sex("man".equalsIgnoreCase(gender) ? 1 : 2).build(), userIds);
        // 5.拼凑vo对象
        List<NearUserVo> nearUserVoList = new ArrayList<>();
        for (UserInfo info : userInfoMap.values()) {
            // 排除自己
            if (Objects.equals(info.getUserId(), UserThreadLocal.getUserId())) {
                continue;
            }
            NearUserVo nearUserVo = new NearUserVo();
            nearUserVo.setUserId(info.getUserId());
            nearUserVo.setAvatar(info.getLogo());
            nearUserVo.setNickname(info.getNickName());
            nearUserVoList.add(nearUserVo);
        }
        return nearUserVoList;
    }

    /**
     * 探花
     *
     * @return
     */
    public List<TodayBest> queryCardsList() {
        // 查询推荐人的列表
        List<Long> exUserIds = new ArrayList<>();
        Collection<String> union = CollUtil.union(
                redisTemplate.opsForSet().members(Constants.USER_LIKE_KEY + UserThreadLocal.getUserId()),
                redisTemplate.opsForSet().members(Constants.USER_NOT_LIKE_KEY + UserThreadLocal.getUserId()));
        for (String s : union) {
            exUserIds.add(Convert.toLong(s));
        }
        List<RecommendUser> recommendUserList = recommendUserApi.queryCardsList(UserThreadLocal.getUserId(), 30, exUserIds);
        // 获取用户id集合
        List<Long> userIds = CollUtil.getFieldValues(recommendUserList, "userId", Long.class);
        // 查询用户信息
        Map<Long, UserInfo> userInfoMap = userInfoApi.findUserInfoByUserIds(userIds);
        // 拼凑vo对象
        List<TodayBest> todayBestVoList = new ArrayList<>();
        for (RecommendUser recommendUser : recommendUserList) {
            TodayBest todayBest = new TodayBest();
            UserInfo info = userInfoMap.get(recommendUser.getUserId());
            todayBest.setId(info.getUserId());
            todayBest.setAvatar(info.getLogo());
            todayBest.setNickname(info.getNickName());
            todayBest.setGender(info.getSex() == 1 ? "man" : "woman");
            todayBest.setAge(info.getAge());
            todayBest.setTags(StrUtil.splitToArray(info.getTags(), ","));
            todayBest.setFateValue(Convert.toLong(recommendUser.getScore()));
            todayBestVoList.add(todayBest);
        }
        return todayBestVoList;
    }

    /**
     * 探花右滑喜欢
     *
     * @param likeUserId
     */
    public void likeUser(Long likeUserId) {
        // 先往user_like表中添加一条数据
        UserLike userLike = new UserLike();
        userLike.setId(new ObjectId());
        userLike.setUserId(UserThreadLocal.getUserId());
        userLike.setLikeUserId(likeUserId);
        userLike.setCreated(System.currentTimeMillis());
        userLikeApi.likeUser(userLike);

        // 把喜欢的人的id缓存到redis中
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserThreadLocal.getUserId(), likeUserId.toString());
    }

    /**
     * 探花左划不喜欢
     *
     * @param likeUserId
     */
    public void notLikeUser(Long likeUserId) {
        // 把不喜欢的人的id缓存到redis中
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserThreadLocal.getUserId(), likeUserId.toString());
    }
}
